package evolution;

public class VersionedDirectoryTreeBuilder
{
	public static final String VERSIONING_DIR = ".versioning";

	private final ResourceFactory resourceFactory;

	private final UUIDGenerator uuidGenerator;

	public VersionedDirectoryTreeBuilder(ResourceFactory resourceFactory, UUIDGenerator uuidGenerator)
	{
		this.resourceFactory = resourceFactory;
		this.uuidGenerator = uuidGenerator;
	}

	public VersionedDirectoryTree initializeRepository(Directory dir) throws VersionedDirectoryTreeException, ResourceException
	{
		if (dir.getMember(".versioning") != null)
		{
			throw new VersionedDirectoryTreeException("Cannot initialize an existing versioned directory tree: " + dir);
		}
		Directory repoDir = resourceFactory.createDirectory(VERSIONING_DIR);
		try
		{
			dir.addMember(repoDir);
		}
		catch (ResourceException e)
		{
			throw new VersionedDirectoryTreeException("Failed to add " + VERSIONING_DIR + " directory", e);
		}
		VersionedDirectoryTree repo = new VersionedDirectoryTree(dir, repoDir, resourceFactory, uuidGenerator);
		VersionedResource rootVersionedResource = repo.addRootResource(dir);
		addResourceMembersToRepositoryRecursively(repo, dir, rootVersionedResource);
		return repo;
	}

	private void addResourceMembersToRepositoryRecursively(VersionedDirectoryTree repo, Resource resource, VersionedResource parent) throws VersionedDirectoryTreeException,
			ResourceException
	{
		if (resource instanceof Directory && resource.getName().equals(VERSIONING_DIR))
		{
			return;
		}
		if (resource instanceof Directory)
		{
			Directory dir = (Directory) resource;
			for (Resource res : dir)
			{
				if (res instanceof Directory && res.getName().equals(VERSIONING_DIR))
				{
					continue;
				}
				VersionedResource el = repo.addResource(res, parent);
				if (res instanceof Directory)
				{
					addResourceMembersToRepositoryRecursively(repo, res, el);
				}
			}
		}
	}

	public VersionedDirectoryTree buildRepository(Directory dir) throws VersionedDirectoryTreeException, ResourceException
	{
		Resource repoDir = dir.getMember(VERSIONING_DIR);
		if (repoDir == null)
		{
			throw new VersionedDirectoryTreeException("Directory is not versioned: " + dir);
		}
		if (repoDir instanceof Directory)
		{
			return new VersionedDirectoryTree(dir, (Directory) repoDir, resourceFactory, uuidGenerator);
		}
		else
		{
			throw new VersionedDirectoryTreeException(VERSIONING_DIR + " must be a directory, it seems to be a file");
		}
	}

	public void wipeRepository(Directory directory) throws VersionedDirectoryTreeException
	{
		if (directory.getMember(VERSIONING_DIR) == null)
		{
			throw new VersionedDirectoryTreeException("Directory is not the root of a versioned directory tree: " + directory);
		}
		directory.deleteMember(VERSIONING_DIR);
	}

}
